Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | export const dynamic = "force-dynamic"; /** * Ticket Survey API * POST /api/support/tickets/[id]/survey - Submit satisfaction survey */ import { NextRequest, NextResponse } from "next/server"; import { Session } from "next-auth"; import { prisma } from "@/lib/prisma"; import { SubmitSurveySchema } from "@/lib/validation/support-schemas"; import { TicketStatus } from "@/types/support"; import { logger } from "@/lib/logging"; import { withErrorHandling, withAuth, createdResponse, ApiError } from "@/lib/api"; import { RouteContext } from "@/lib/api/middleware"; /** * POST /api/support/tickets/[id]/survey * Submit satisfaction survey for a resolved/closed ticket */ async function handlePost( request: NextRequest, context: RouteContext | undefined, session: Session ): Promise<NextResponse> { if (!context?.params) { throw ApiError.invalidId("ticket"); } const { id } = await context.params; const userId = Number(session.user.id); // Verify ticket exists and belongs to user const ticket = await prisma.supportTicket.findUnique({ where: { id }, include: { survey: true, assignedTo: { select: { id: true }}}}); if (!ticket) { throw ApiError.notFound("Ticket", id); } if (ticket.userId !== userId) { throw ApiError.forbidden("Access denied"); } // Check if ticket is resolved or closed if ( ticket.status !== TicketStatus.RESOLVED && ticket.status !== TicketStatus.CLOSED ) { throw ApiError.validation("Survey can only be submitted for resolved tickets"); } // Check if survey already exists if (ticket.survey) { throw ApiError.validation("Survey already submitted for this ticket"); } // Validate input const body = await request.json(); const validationResult = SubmitSurveySchema.safeParse(body); if (!validationResult.success) { throw ApiError.validation( "Validation failed", validationResult.error.flatten().fieldErrors ); } const data = validationResult.data; // Create the survey const survey = await prisma.ticketSurvey.create({ data: { ticketId: id, rating: data.rating, feedback: data.feedback || null, wasHelpful: data.wasHelpful ?? null, wouldRecommend: data.wouldRecommend ?? null}}); // Update agent's average rating if assigned if (ticket.assignedToId) { // Get all surveys for this agent const agentSurveys = await prisma.ticketSurvey.findMany({ where: { ticket: { assignedToId: ticket.assignedToId}}, select: { rating: true }}); const avgRating = agentSurveys.reduce((sum, s) => sum + s.rating, 0) / agentSurveys.length; await prisma.supportAgentProfile.upsert({ where: { userId: ticket.assignedToId }, update: { customerRating: avgRating }, create: { userId: ticket.assignedToId, customerRating: avgRating}}); } logger.info("Ticket survey submitted", { category: "API", ticketId: id, rating: data.rating, userId}); return createdResponse({ ...survey, message: "Thank you for your feedback!"}); } export const POST = withErrorHandling(withAuth(handlePost)); |